package vip.web3.api.service.impl.biz;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import vip.web3.admin.sys.entity.biz.AOrderEntity;
import vip.web3.admin.sys.service.sys.SysConfigService;
import vip.web3.api.constans.RedisConstant;
import vip.web3.api.constans.enums.UserEditEnum;
import vip.web3.api.dao.biz.OrderDao;
import vip.web3.api.dao.biz.RecordDao;
import vip.web3.api.dao.biz.UserDao;
import vip.web3.api.dao.biz.UserWalletDao;
import vip.web3.api.entity.biz.OrderEntity;
import vip.web3.api.entity.biz.UserEntity;
import vip.web3.api.entity.biz.UserWalletEntity;
import vip.web3.api.form.user.AuthApplyForm;
import vip.web3.api.form.user.EditForm;
import vip.web3.api.form.user.LoginForm;
import vip.web3.api.mapper.UserMapper;
import vip.web3.api.service.base.Web3jApiService;
import vip.web3.api.service.biz.UserService;
import vip.web3.api.vo.base.WalletVo;
import vip.web3.api.vo.biz.InviteUserVo;
import vip.web3.api.vo.biz.TeamInfoVo;
import vip.web3.api.vo.biz.UserInfoVo;
import vip.web3.common.enums.*;
import vip.web3.common.enums.user.PwdTypeEnum;
import vip.web3.common.enums.user.UserAuthEnum;
import vip.web3.common.exception.RRException;
import vip.web3.common.utils.AES;
import vip.web3.common.utils.RedisUtils;
import vip.web3.common.utils.Servlets;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * aut-horlilei
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    private UserWalletDao userWalletDao;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private RecordDao recordDao;

    @Autowired
    private RedisUtils redisUtils;


    @Autowired
    private Web3jApiService web3jApiService;
    @Resource
    private SysConfigService configService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String register(UserEntity entity) {

        List<UserEntity> list = this.lambdaQuery().eq(UserEntity::getMobile, entity.getMobile()).list();
        if (!CollectionUtils.isEmpty(list)) {
            throw new RRException("该手机已被注册!", -1);
        }

        UserEntity byInviteCode = this.lambdaQuery().eq(UserEntity::getInviteCode, entity.getInviteCode()).one();
        if (byInviteCode == null) {
            throw new RRException("邀请码不存在!", -1);
        }

        entity.setPath(byInviteCode.getId());
        entity.setPath2(byInviteCode.getPath());
        entity.setPath3(byInviteCode.getPath2());
        entity.setRoute(byInviteCode.getRoute() + byInviteCode.getId() + "/");


        String inviteCode = RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER_LOWER, 8);
        UserEntity one = this.lambdaQuery().eq(UserEntity::getInviteCode, inviteCode).one();
        if (Objects.nonNull(one)) {
            throw new RRException("注册失败,请稍后重试", -1);
        }

        entity.setNick("****" + entity.getMobile().substring(4));
        entity.setGender(GenderEnum.MALE.getCode());
        entity.setPassword(DigestUtils.sha256Hex(entity.getPassword()));
        entity.setFundPassword(DigestUtils.sha256Hex(entity.getFundPassword()));
        entity.setInviteCode(inviteCode);
        // 等级字段默认值
        entity.setTeamLevel(0);
        entity.setTeamName(null);
        entity.setTeamSustain(0);
        entity.setPersonalLevel(0);
        entity.setPersonalName(null);
        entity.setQuarterLevel(0);
        entity.setQuarterName(null);
        // 充值提现 usdt 地址和私钥
        WalletVo walletVo = web3jApiService.createWallet();
        if (walletVo != null) {
            String encryptBsc = AES.encrypt("pYwPdQ1XYEVELgAHvpx/RA==", walletVo.getPrivateKey());
            entity.setBscAddress(walletVo.getAddress());
            entity.setBscPrivate(encryptBsc);
        }

        entity.setTronAddress(null);
        entity.setTronPrivate(null);
        entity.setActive(ActiveEnum.NO_ACTIVE.getCode());
        entity.setStatus(StatusEnum.OPEN.getCode());
        entity.setAuthStatus(UserAuthEnum.NO_AUTH.getCode());
        entity.setCreateTime(new Date());
        int insert = this.baseMapper.insert(entity);
        if (insert < 1) {
            throw new RRException("注册失败,请稍后重试!", -1);
        }

        UserWalletEntity userWalletEntity = new UserWalletEntity();
        userWalletEntity.setUserId(entity.getId());
        userWalletEntity.setType(WalletTypeEnum.UNKNOWN.getCode());
        userWalletEntity.setAmountCny(BigDecimal.ZERO);
        userWalletEntity.setAmountUsdt(BigDecimal.ZERO);
        userWalletEntity.setWithdrawCny(BigDecimal.ZERO);
        userWalletEntity.setWithdrawUsdt(BigDecimal.ZERO);
        userWalletEntity.setCreateDate(new Date());
        userWalletEntity.setUpdateDate(new Date());

        int inserted = this.userWalletDao.insert(userWalletEntity);
        if (inserted < 1) {
            throw new RRException("注册失败,请稍后重试!!", -1);
        }
        String token = UUID.randomUUID().toString().replace("-", "");
        // 有效期12小时
        return token;
    }

    @Override
    public String login(LoginForm form) {
        UserEntity userEntity = this.lambdaQuery().select(UserEntity::getPassword, UserEntity::getId, UserEntity::getMobile, UserEntity::getStatus).eq(UserEntity::getMobile, form.getMobile()).one();
        if (Objects.isNull(userEntity)) {
            throw new RRException("账号或者密码错误!", -1);
        }

        String password = userEntity.getPassword();
        if (!DigestUtils.sha256Hex(form.getPassword()).equals(password)) {
            throw new RRException("账号或者密码错误", -1);
        }
        if (!userEntity.getStatus().equals(1)) {
            throw new RRException("用户状态异常", -1);
        }

        String loginIdKey = "alloytech:user:login:id:" + userEntity.getId();
        String loginIdStr = redisUtils.get(loginIdKey);
        if (!StringUtils.isBlank(loginIdStr)) {
            redisUtils.delete("alloytech:user:login:token:" + loginIdStr);
        }
        String token = UUID.randomUUID().toString().replace("-", "");
        String key = "alloytech:user:login:token:" + token;
        redisUtils.set(loginIdKey, token);
        // 有效期12小时
        redisUtils.set(key, userEntity.getId(), 12 * 60 * 60);
        log.info("登录成功 token:{} , form:{}", token, form);
        redisUtils.hset(RedisConstant.USER_INFO, form.getMobile(), JSONObject.toJSONString(userEntity), -1);
        return token;

    }

    @Override
    public void logout() {
        String key = "alloytech:user:login:token:" + Servlets.getToken();
        String userIdStr = redisUtils.get(key);
        String loginIdKey = "alloytech:user:login:id:" + userIdStr;
        redisUtils.delete(key);
        redisUtils.delete(loginIdKey);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePwd(EditForm form) {

        UserEntity userEntity = this.baseMapper.selectById(Servlets.getUserId());
        if (PwdTypeEnum.PWD.equals(PwdTypeEnum.get(form.getType()))) {
            if (!DigestUtils.sha256Hex(form.getOldPassword()).equals(userEntity.getPassword())) {
                throw new RRException("原密码错误", -1);
            }
            userEntity.setPassword(DigestUtils.sha256Hex(form.getPassword()));
        } else {
            if (!DigestUtils.sha256Hex(form.getOldPassword()).equals(userEntity.getFundPassword())) {
                throw new RRException("原密码错误", -1);
            }
            userEntity.setFundPassword(DigestUtils.sha256Hex(form.getPassword()));
        }
        int inserted = this.baseMapper.updateById(userEntity);
        if (inserted < 1) {
            throw new RRException("修改密码失败,请稍后重试!!", -1);
        }
    }

    @Override
    public void edit(EditForm form) {
        UserEditEnum editEnum = Objects.requireNonNull(UserEditEnum.get(form.getType()), "修改类型错误");
        editEnum.valid(form);

        LambdaUpdateChainWrapper<UserEntity> wrapper = this.lambdaUpdate();
        if (UserEditEnum.NICK.equals(editEnum)) {
            editEnum.check(() -> {
                List<UserEntity> list = this.lambdaQuery()
                        .eq(UserEntity::getNick, form.getNick())
                        .ne(UserEntity::getId, Servlets.getUserId())
                        .list();
                if (!CollectionUtils.isEmpty(list)) {
                    throw new RRException("该昵称已存在!", -1);
                }
            });
            wrapper.set(UserEntity::getNick, form.getNick());
        }
        if (UserEditEnum.GENDER.equals(editEnum)) {
            wrapper.set(UserEntity::getGender, form.getGender());
        }
        if (UserEditEnum.HEAD.equals(editEnum)) {
            wrapper.set(UserEntity::getHeadUrl, form.getHeadUrl());
        }

        boolean updated = wrapper
                .eq(UserEntity::getId, Servlets.getUserId()).update();
        if (!updated) {
            throw new RRException("修改会员信息失败,请稍后重试!!", -1);
        }
    }

    @Override
    public void authApply(AuthApplyForm form) {

        UserEntity userEntity = new UserEntity();
        userEntity.setAuthStatus(UserAuthEnum.AUTH_APPLY.getCode());
        userEntity.setRealName(form.getRealName());
        userEntity.setIdNo(form.getIdNo());
        userEntity.setIdUrl(form.getIdUrl());
        userEntity.setIdBackUrl(form.getIdBackUrl());
        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserEntity::getId, Servlets.getUserId());
        int updated = this.baseMapper.update(userEntity, updateWrapper);
        if (updated < 1) {
            throw new RRException("申请实名认证失败,请稍后重试!!", -1);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMobile(EditForm form) {

        UserEntity userEntity = this.baseMapper.selectById(Servlets.getUserId());
        if (!DigestUtils.sha256Hex(form.getPassword()).equals(userEntity.getPassword())) {
            throw new RRException("账号或密码错误", -1);
        }
        List<UserEntity> list = this.lambdaQuery().eq(UserEntity::getMobile, form.getMobile()).list();
        if (!CollectionUtils.isEmpty(list)) {
            throw new RRException("该手机已被注册!", -1);
        }

        userEntity.setMobile(form.getMobile());
        int inserted = this.baseMapper.updateById(userEntity);
        if (inserted < 1) {
            throw new RRException("修改手机号失败,请稍后重试!!", -1);
        }
    }

    @Override
    public UserInfoVo info() {
        String shareUrl = configService.getValue("share_url");
        if (null == shareUrl) {
            shareUrl = "https://hjzg.cc/#/?invitationCode=";
        }


        UserEntity userEntity = this.baseMapper.selectById(Servlets.getUserId());

        UserWalletEntity userWalletEntity = this.userWalletDao
                .selectOne(Wrappers.<UserWalletEntity>lambdaQuery().eq(UserWalletEntity::getUserId, Servlets.getUserId()));

        return UserMapper.INSTANCE.mergeUserInfoVo(userEntity, userWalletEntity, shareUrl);
    }

    @Override
    public List<InviteUserVo> listInvite(Integer level) {

        if (Objects.isNull(level) || level < 1 || level > 3) {
            throw new RRException("等级参数错误!!", -1);
        }
        return this.baseMapper.listInvite(Servlets.getUserId(), level);
    }

    @Override
    public TeamInfoVo teamInfo() {
        Integer userId = Servlets.getUserId();

        TeamInfoVo teamInfoVo = new TeamInfoVo();
        Integer totalRegister = this.lambdaQuery()
                .eq(UserEntity::getPath, userId)
                .or()
                .eq(UserEntity::getPath2, userId)
                .or()
                .eq(UserEntity::getPath3, userId).count();
        teamInfoVo.setTotalTeamRegister(totalRegister);

        LocalDate now = LocalDate.now();
        Integer todayRegister = this.lambdaQuery()
                .ge(UserEntity::getCreateTime, now)
                .lt(UserEntity::getCreateTime, now.plusDays(1))
                .and(wrapper -> wrapper.eq(UserEntity::getPath, userId)
                        .or()
                        .eq(UserEntity::getPath2, userId)
                        .or()
                        .eq(UserEntity::getPath3, userId)).count();
        teamInfoVo.setTodayTeamRegister(todayRegister);

        QueryWrapper<OrderEntity> query = new QueryWrapper<>();
        query.ne("pro_id", 1);
        query.inSql("user_id",
                "select id from a_user where path = " + userId + " or path2 = " + userId + " or path3 = " + userId);
        Integer totalActive = orderDao.selectCount(query);

        teamInfoVo.setTotalTeamActive(totalActive);

        QueryWrapper<OrderEntity> query2 = new QueryWrapper<>();
        query2.ne("pro_id", 1);
        query2.le("create_date", now);
        query2.ge("create_date", now.minusDays(1));
        query2.inSql("user_id",
                "select id from a_user where path = " + userId + " or path2 = " + userId + " or path3 = " + userId);
        Integer yesterdayActive = orderDao.selectCount(query2);
        teamInfoVo.setYesterdayTeamActive(yesterdayActive);

        OrderEntity totalTeamInvest = this.orderDao.totalTeamInvest(userId);
        BigDecimal totalTeamInvestCny = Objects.nonNull(totalTeamInvest) ? totalTeamInvest.getAmountCny() : BigDecimal.ZERO;
        BigDecimal totalTeamInvestUsdt = Objects.nonNull(totalTeamInvest) ? totalTeamInvest.getAmountUsdt() : BigDecimal.ZERO;
        teamInfoVo.setTotalTeamInvestCny(totalTeamInvestCny.stripTrailingZeros().toPlainString());
        teamInfoVo.setTotalTeamInvestUsdt(totalTeamInvestUsdt.stripTrailingZeros().toPlainString());

        BigDecimal todayBrokerage = this.recordDao.todayBrokerages(userId);
        todayBrokerage = Objects.isNull(todayBrokerage) ? BigDecimal.ZERO : todayBrokerage;
        teamInfoVo.setTodayBrokerage(todayBrokerage.stripTrailingZeros().toPlainString());
        return teamInfoVo;
    }

    public UserEntity getUserByToken(HttpServletRequest request) {
        try {
            String token = request.getHeader("token");
            String token_ = request.getParameter("token");
            if (org.apache.commons.lang.StringUtils.isBlank(token)) {
                token = token_;
            }
            if (StringUtils.isBlank(token)) {
                return null;
            }
            token = "alloytech:user:login:token:" + token;
            String id = redisUtils.get(token);
            if (StringUtils.isBlank(id)) {
                return null;
            }
            UserEntity user = baseMapper.selectById(id);
            if (user != null) {
                return user;
            }
            return null;
        } catch (Exception ex) {
            return null;
        }
    }

}
